package org.ants.tinymvc.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.ants.tinymvc.entity.BaseEntity;
import org.ants.tinymvc.enums.DelFlagEnum;
import org.ants.tinymvc.exception.DataAccessException;
import org.apache.commons.lang.StringUtils;
import org.tinygroup.beancontainer.BeanContainerFactory;
import org.tinygroup.commons.tools.CollectionUtil;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;
import org.tinygroup.tinydb.Bean;
import org.tinygroup.tinydb.DbOperatorFactory;
import org.tinygroup.tinydb.Pager;
import org.tinygroup.tinydb.exception.TinyDbException;
import org.tinygroup.tinydb.operator.DBOperator;
import org.tinygroup.tinydb.order.OrderBean;
import org.tinygroup.tinydb.query.Conditions;

/**
 * 数据库操作基础类
 * @author laibingrong
 *
 * @param <T>
 * @param <PK>
 */
@SuppressWarnings("rawtypes")
public abstract class BaseTinyDbDao<T extends BaseEntity> {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	//主键规定为String类型。
	private DBOperator<String> operator;
	
	private DbOperatorFactory factory;
	
	/*
	 * 数据库表的属性名（驼峰模式）
	 */
	protected String beanType;
	
	/*数据库表名
	 * 
	 */
	protected String tableName;
	
	public abstract String getBeanType();
	
	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	@SuppressWarnings("unchecked")
	private void init(){
	   factory = BeanContainerFactory.getBeanContainer(
				getClass().getClassLoader()).getBean("tinyDBOperatorFactory");
	   operator = factory.getDBOperator();
	}
	
	public BaseTinyDbDao(){
		init();
	}

	public BaseEntity insert(T t) throws Exception {
		Bean bean = this.insert(t.toBean());
		return t.fromBean(bean);
	}
	
	public Bean insert(Bean bean){
		//TODO 从缓存读取用户信息
		return this.getOperator().insert(bean);
	}

	public int update(T t) throws Exception {
		return this.update(t.toBean());
	}
	
	public int update(Bean bean) throws Exception {
		//TODO 从缓存读取用户信息
		int record = this.getOperator().update(bean);
		return record;
	}

	public int deleteByKey(String key,boolean flag) throws Exception {
		if(flag){
			return this.deleteByKey(key);
		}
		Bean bean = this.findBeanByKey(key);
		bean.setProperty("DEL_FLAG", DelFlagEnum.DELETED.getKey());//软删除
		return this.update(bean);
	}
	
	public int deleteByKey(String id) throws Exception {
		Bean bean = this.findBeanByKey(id);
		if(bean == null || bean.size()==0){
			return 0;
		}
		return this.getOperator().deleteById(id,this.getBeanType());
	}

	public int deleteByKeys(String... keys) throws Exception {
		int index = 0;
		if(keys == null || keys.length == 0){
			return index;
		}
		for(String key : keys){
			index += this.deleteByKey(key);
		}
		return index;
	}
	
	public int deleteByKeys(boolean flag, String... keys) throws Exception {
		int index = 0;
		if (keys == null || keys.length == 0) {
			return index;
		}
		for (String key : keys) {
			index += this.deleteByKey(key, flag);
		}
		return index;
	}

	public int deleteBeans(Bean... beans) throws Exception{
		int[] records = this.getOperator().deleteBean(beans);
		int result = 0;
		for(int record : records){
			result += record;
		}
		return result;
	}
	
	public int deleteBeans(boolean flag,Bean... beans) throws Exception{
		if(flag){
			return this.deleteBeans(beans);
		}
		for(Bean bean : beans){
			bean.setProperty("DEL_FLAG", DelFlagEnum.DELETED.getKey());//软删除
		}
		int[] records = this.getOperator().updateBean(beans);
		int result = 0;
		for(int record : records){
			result += record;
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public T findObjectByKey(String key,T t) throws Exception {
		Bean bean = this.getOperator().getBean(key, this.getBeanType());
		return (T) t.fromBean(bean);
	}
	
	public Bean[] findBeans(Bean bean){
		if(StringUtils.isEmpty(bean.getType())){
			bean.setType(this.getBeanType());
		}
		return this.getOperator().getBeans(bean);
	}
	
	public Bean findBeanByKey(String key) throws Exception {
		Bean bean = this.getOperator().getBean(key, this.getBeanType());
		return  bean;
	}
	 
    public Bean findByPkWithLock(String id) {
    	StringBuffer sbsql = new StringBuffer();
    	sbsql.append("SELECT * FROM ");
    	sbsql.append(this.getTableName());
    	sbsql.append(" WHERE ID = ");
    	sbsql.append(id);
    	sbsql.append(" FOR UPDATE ");
    	try{
    		Bean[] bean = this.getOperator().getBeans(sbsql.toString());
	        return bean[0];
	    }catch(Exception ex){
			logger.error("sql执行错误：", ex);
			throw new DataAccessException(ex);
		}
    }
    
    public List<Bean> findAll() {
    	try{
    		Bean bean = new Bean(this.getBeanType());
    		Bean[] beans = this.getOperator().getBeans(bean);
    		return CollectionUtil.asList(beans);
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
    
    public List<Bean> findByCondition(Conditions qc,OrderBean[] orderBeans){
    	try{
    		Bean[] beans = this.getOperator().getBeans(this.getBeanType(), qc, orderBeans);
    		return CollectionUtil.asList(beans);
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
    
    public Bean findSigleByCondition(Conditions qc){
    	try{
    		List<Bean> beans = this.findByCondition(qc, null);
    		if(beans == null || beans.size() == 0){
    			return null;
    		}
    		return beans.get(0);
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
    
    @SuppressWarnings("unchecked")
	public T findSingleByCondition(Conditions qc,T t){
    	try{
    		List<Bean> beans = this.findByCondition(qc, null);
    		if(beans == null || beans.size() == 0){
    			return null;
    		}
    		return (T) t.fromBean(beans.get(0));
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
    
    
    public List<Bean> findForList(String sql) {
    	try{
    		Bean[] beans = this.getOperator().getBeans(sql);
	        return CollectionUtil.asList(beans);
	    }catch(Exception ex){
			logger.error("sql执行错误：", ex);
			throw new DataAccessException(ex);
		}
    }
    
    @SuppressWarnings("unchecked")
	public List<T> findForList(String sql, T entity) {
    	try{
    		Bean[] beans = this.getOperator().getBeans(sql);
    		List<T> list = new ArrayList();
    		if(beans == null || beans.length == 0){
    			return list;
    		}
    		for(Bean bean : beans){
    			list.add((T) entity.fromBean(bean));
    		}
	    	return list;
	    }catch(Exception ex){
			logger.error("sql执行错误：", ex);
			throw new DataAccessException(ex);
		}
    }
    
    public List<Bean> findForLimitList(Conditions qc,OrderBean[] orderBean,int begin, int end) {
        try{
        	Bean[] beans = this.getOperator().getBeans(this.getBeanType(), qc, orderBean, begin, end);
        	 return CollectionUtil.asList(beans);
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
    
    public List<Bean> findForLimitList(Conditions qc,int begin, int end) {
        try{
        	Bean[] beans = this.getOperator().getBeans(this.getBeanType(), qc, null, begin, end);
        	return CollectionUtil.asList(beans);
    	}catch(Exception ex){
    		logger.error("sql执行错误：", ex);
    		throw new DataAccessException(ex);
    	}
    }
 
    public Bean[] batchInsertBeans(List<Bean> beans) throws Exception {
		return this.getOperator().batchInsert(beans);
	}
    
    public Bean[] batchInsertBeans(List<Bean> beans,int batchSize) throws Exception {
		return this.getOperator().batchInsert(beans,batchSize);
	}
	
	public Bean[] batchInsert(List<T> entitys,int batchSize) throws Exception {
		List<Bean> beans = new ArrayList<Bean>();
		for(T t : entitys){
			beans.add(t.toBean());
		}
		return this.getOperator().batchInsert(beans,batchSize);
	}
    
    public Bean[] batchInsert(List<T> entitys) throws Exception {
		List<Bean> beans = new ArrayList<Bean>();
		for(T t : entitys){
			beans.add(t.toBean());
		}
		return this.getOperator().batchInsert(beans);
	}

    public int[] batchUpdate(List<T> entitys) throws Exception {
    	List<Bean> beans = new ArrayList<Bean>();
		for(T t : entitys){
			beans.add(t.toBean());
		}
		return this.getOperator().batchUpdate(beans);
	}
	
	public void batchUpdate(List<T> entitys, int batchSize) throws Exception {
		List<Bean> beans = new ArrayList<Bean>();
		for (T t : entitys) {
			beans.add(t.toBean());
		}
	   this.getOperator().batchUpdate(beans, batchSize);
	}

	public int[] batchUpdateBeans(Bean[]  beans) {
		return this.getOperator().batchUpdate(beans);
	}
	
	public Bean[] batchUpdateBeans(List<Bean> beans,int batchSize) {
		return this.getOperator().batchInsert(beans,batchSize);
	}

	public int[] batchDelete(List<T> entitys) throws Exception {
		List<Bean> beans = new ArrayList<Bean>();
		for (T t : entitys) {
			beans.add(t.toBean());
		}
		return this.batchDeleteBean(beans);
	}
	
	public void batchDelete(List<T> entitys,int batchSize) throws Exception {
		List<Bean> beans = new ArrayList<Bean>();
		for (T t : entitys) {
			beans.add(t.toBean());
		}
		this.batchDeleteBean(beans, batchSize);
	}
	
	public int[] batchDeleteBean(List<Bean> beans) {
		return this.getOperator().batchDelete(beans);
	}

	public void batchDeleteBean(List<Bean> beans,int batchSize) {
		this.getOperator().batchDelete(beans,batchSize);
	}
	
	public DBOperator<String> getOperator() {
		return operator;
	}
	
	  //查询总记录数
    public int account(String sql, Object... parameters) throws TinyDbException{
    	return this.getOperator().account(sql, parameters);
    }

    public int account(String sql, List<Object> parameters) throws TinyDbException{
    	return this.getOperator().account(sql, parameters);
    }

    public int account(String sql, Map<String, Object> parameters) throws TinyDbException{
    	return this.getOperator().account(sql, parameters);
    }

    public int account(Bean bean) throws TinyDbException{
    	return this.getOperator().account(bean);
    }

    //返回分页结果的分页接口
    public Pager getPager(String sql, int start, int limit) throws TinyDbException{
    	return this.getOperator().getPager(sql, start, limit);
    }

    public Pager getPager(String sql, int start, int limit, Object... parameters) throws TinyDbException{
    	return this.getOperator().getPager(sql, start, limit, parameters);
    }

    public Pager getPager(String sql, int start, int limit, List<Object> parameters) throws TinyDbException{
    	return this.getOperator().getPager(sql, start, limit, parameters);
    }

    public Pager getPager(String sql, int start, int limit, Map<String, Object> parameters) throws TinyDbException{
    	return this.getOperator().getPager(sql, start, limit, parameters);
    }

    public Bean[] getBeans(Bean bean, int start, int limit) throws TinyDbException{
    	return this.getOperator().getBeans(bean, start, limit);
    }

    public  Pager getPager(Bean bean, int start, int limit) throws TinyDbException{
    	return this.getOperator().getPager(bean, start, limit);
    }

}
